﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GN.Pay.Application.MerchantApp.Dto.Input;
using GN.Pay.Application.MerchantApp.Dto.Output;
using GN.Pay.Core.Repositories;
using GN.Framework.Extensions;
using Abp.AutoMapper;
using GN.Pay.Core.Entities;
using GN.Pay.Core.Startup;
using GN.Pay.TradeChannel;
using System.Security.Cryptography;
using GN.Pay.Core.Runtime;
using GN.Pay.Utils.Security;
using GN.Pay.Core.Runtime.Caching;
using GN.Pay.Core.Services;
using GN.Pay.TradeChannel.Configure;

namespace GN.Pay.Application.MerchantApp.Impl
{
    /// <summary>
    /// 
    /// </summary>
    public class MerchantAppChannelAppService : MerchantAppService, IMerchantAppChannelAppService
    {
        private readonly IMerchantAppChannelRepository repository;
        private readonly IMerchantAppInfoRepository appRepository;
        private readonly ISystemConfigureRepository configRepository;
        private readonly IAppSecurity appSecurity;
        private readonly ITradeCacheService tradeCacheService;

        public MerchantAppChannelAppService(IMerchantAppChannelRepository repository,
            IMerchantAppInfoRepository appRepository,
            ISystemConfigureRepository configRepository,
            IAppSecurity appSecurity,
            ITradeCacheService tradeCacheService)
        {
            this.repository = repository;
            this.appRepository = appRepository;
            this.configRepository = configRepository;
            this.appSecurity = appSecurity;
            this.tradeCacheService = tradeCacheService;
        }


        private ITradeChannel CheckChannel(MerchantAppChannelRegisterInput input, out string json)
        {
            var type = TradeChannelInstaller.Instance.GetTradeChannelType(input.ChannelId);
            if (type == null)
            {
                throw new Abp.UI.UserFriendlyException("指定的支付通道不支持或未开通");
            }
            json = input.ConfigureInfo.ToJson(true);
            var channel = (ITradeChannel)Activator.CreateInstance(type);
            var configInfo = json.JsonToObject(channel.TradeChannelConfigureInfoType, true) as ITradeChannelConfigureInfo;
            channel.ChannelConfigure.SaveCheck(configInfo);
            return channel;
        }

        public MerchantAppChannelOutput RegisterOrUpdate(MerchantAppChannelRegisterInput input)
        {
            string json;
            var channel = CheckChannel(input, out json);
            var app = appRepository.Get(input.AppId);
            if (app == null)
            {
                throw new Abp.UI.UserFriendlyException("应用未注册");
            }
            //验证商户

            var info = appSecurity.Decrypt(app);

            var entity = repository.FirstOrDefault(s => s.AppId == app.Id && s.ChannelId == input.ChannelId);
            if (entity == null)
            {
                entity = input.MapTo<MerchantAppChannel>();
                entity.ChannelName = channel.ChannelName;
                entity.ConfigureData = RsaUtils.Encrypt(info.PublicKey, json);
                entity.CreationTime = DateTime.Now;
                entity.LastModificationTime = null;
                entity.State = 1;
                entity.ChannelType = (int)channel.ChannelType;                

                tradeCacheService.RemoveTradeChannels(entity.AppId);

                repository.Insert(entity);
            }
            else
            {
                entity.ConfigureData = RsaUtils.Encrypt(info.PublicKey, json);
                entity.LastModificationTime = DateTime.Now;
                entity.ChannelType = (int)channel.ChannelType;

                tradeCacheService.RemoveTradeChannel(entity.AppId, entity.ChannelId);
                tradeCacheService.RemoveTradeChannels(entity.AppId);

                repository.Update(entity);
            }
            repository.SaveChanges();
            return entity.MapTo<MerchantAppChannelOutput>();
        }
    }
}
